package com.share.schedule.simple.config;

import com.share.schedule.simple.model.db.ScheduleJob;
import com.share.schedule.simple.schedule.BaseJob;
import com.share.schedule.simple.service.ScheduleJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 01401061 - 孙艳强
 * @date 2020/12/4 12:55
 */
@Slf4j
@Component
public class SchedulerBuilder {
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ScheduleJobService scheduleJobSvice;

    /**
     * 手动创建Scheduler
     */
    @PostConstruct
    public void initScheduler() {
        //1.读取配置
        Map<String, ScheduleJob> jobConfigMap = scheduleJobSvice.mapAllTask();
        if (jobConfigMap == null) {
            return;
        }

        //2.实例化trigger
        log.info("----------------------------正在初始化配置定时任务----------------------------------");
        Map<String, Trigger> triggerMap = new HashMap<>();
        Map<String, BaseJob> baseJobMap = applicationContext.getBeansOfType(BaseJob.class);
        baseJobMap.values().forEach(jobInstance -> {
            String jobCode = jobInstance.getJobCode();
            log.info("定时任务类的配置jobCode=" + jobCode + ",class=" + jobInstance.getClass());
            ScheduleJob scheduleJob = jobConfigMap.get(jobCode);
            if (scheduleJob != null) {
                JobDetail jobDetail = createJobDetail(jobInstance);
                Trigger cronTrigger = createCronTrigger(scheduleJob, jobDetail);
                if (jobDetail != null && cronTrigger != null) {
                    triggerMap.put(jobCode, cronTrigger);
                } else {
                    log.info("定时任务加载失败jobCode=" + jobCode);
                }
            }
        });


        //3.实例化到
        if (CollectionUtils.isEmpty(triggerMap)) {
            log.info("本次不加载任何定时任务,class=" + this.getClass());
        } else {
            SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
            schedulerFactoryBean.setTriggers((Trigger[]) triggerMap.values().toArray(new Trigger[triggerMap.size()]));
            schedulerFactoryBean.setApplicationContext(this.applicationContext);
            try {
                /*启动定时器*/
                schedulerFactoryBean.setStartupDelay(3);//设置延迟
                schedulerFactoryBean.setAutoStartup(true);

                schedulerFactoryBean.afterPropertiesSet();//组装结构

                log.info("即将启动定时任务");
                schedulerFactoryBean.start();
                log.info("定时任务启动成功！！！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private Trigger createCronTrigger(ScheduleJob taskJob, JobDetail jobDetail) {
        if (jobDetail == null) {
            return null;
        }
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setCronExpression(taskJob.getCronExpress());
        cronTriggerFactoryBean.setJobDetail(jobDetail);
        cronTriggerFactoryBean.setName(taskJob.getJobCode());
        try {
            /*执行构建*/
            cronTriggerFactoryBean.afterPropertiesSet();
            return cronTriggerFactoryBean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private JobDetail createJobDetail(BaseJob job) {
        MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
        methodInvokingJobDetailFactoryBean.setConcurrent(false);
        methodInvokingJobDetailFactoryBean.setTargetObject(job);
        methodInvokingJobDetailFactoryBean.setTargetMethod("execute");
        methodInvokingJobDetailFactoryBean.setName(job.getJobCode());
        try {
            /*执行构建*/
            methodInvokingJobDetailFactoryBean.afterPropertiesSet();
            return methodInvokingJobDetailFactoryBean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
